package com.ruoyi.web.controller.system;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.core.domain.entity.SysDept;

import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.exception.CustomException;
import com.ruoyi.system.service.ISysDeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.service.ISysPostService;
import com.ruoyi.system.service.ISysRoleService;
import com.ruoyi.system.service.ISysUserService;

/**
 * 用户信息
 *
 * @author ruoyi
 */
@RestController
@RequestMapping("/system/user")
public class SysUserController extends BaseController
{
    @Autowired
    private ISysUserService userService;

    @Autowired
    private ISysRoleService roleService;

    @Autowired
    private ISysPostService postService;

    @Autowired
    private TokenService tokenService;
    //客户角色Id
    @Value("${sysUser.customerRoleId:105}")
    private Long customerRoleId;
    //巡检工角色Id
    @Value("${sysUser.inspectorRoleId:104}")
    private Long inspectorRoleId;
    //产品管理员角色Id（设计员）
    @Value("${sysUser.commonRoleId:2}")
    private Long commonRoleId;
    //巡检工角色用户数量上限
    @Value("${sysUser.inspectorMaxSize:10}")
    private Integer inspectorMaxSize;
    /**
     * 现场工程师
     */
    @Value("${sysUser.sceneRoleId:102}")
    private Long sceneRoleId;

    /**
     * 公司管理员
     */
    @Value("${sysUser.companyRoleId:3}")
    private Long companyRoleId;
    /**
     * 安装工角色Id
     */
    @Value("${sysUser.installerRoleId:103}")
    private Long installerRoleId;

    @Autowired
    private ISysDeptService sysDeptService;

    /**
     * 获取用户列表
     */
    @PreAuthorize("@ss.hasPermi('system:user:list')")
    @GetMapping("/list")
    public TableDataInfo list(SysUser user)
    {
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        SysDept dept = loginUser.getUser().getDept();
        user = user == null ? new SysUser() : user;
        Long deptId = null;
        if (user.getDeptId() == null){
            //获取当前公司
            if (!loginUser.getUser().isAdmin()){
                Long deptId1 = dept.getDeptId();
                if (sysDeptService.checkIsCustomer(Convert.toLong(deptId1))){
                    deptId = sysDeptService.getCustomerId(deptId1);
                }else if (dept.getParentId() == 0L){
                    deptId = dept.getDeptId();
                }else {
                    deptId = Convert.toLong(StrUtil.splitTrim(dept.getAncestors(),",").get(1));
                }
            }
            user.setDeptId(deptId);
        }
        startPage();
        List<SysUser> list = userService.selectUserList(user);
        return getDataTable(list);
    }

    @Log(title = "用户管理", businessType = BusinessType.EXPORT)
    @PreAuthorize("@ss.hasPermi('system:user:export')")
    @GetMapping("/export")
    public AjaxResult export(SysUser user)
    {
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        SysDept dept = loginUser.getUser().getDept();
        user = user == null ? new SysUser() : user;
        Long deptId = null;
        if (user.getDeptId() == null){
            //获取当前公司
            if (!loginUser.getUser().isAdmin()){
                if (dept.getParentId() == 0L){
                    deptId = dept.getDeptId();
                }else {
                    deptId = Convert.toLong(StrUtil.splitTrim(dept.getAncestors(),",").get(1));
                }
            }
            user.setDeptId(deptId);
        }
        List<SysUser> list = userService.selectUserList(user);
        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
        return util.exportExcel(list, "用户数据");
    }

    @Log(title = "用户管理", businessType = BusinessType.IMPORT)
    @PreAuthorize("@ss.hasPermi('system:user:import')")
    @PostMapping("/importData")
    public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
    {
        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
        List<SysUser> userList = util.importExcel(file.getInputStream());
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        String operName = loginUser.getUsername();
        String message = userService.importUser(userList, updateSupport, operName);
        return AjaxResult.success(message);
    }

    @GetMapping("/importTemplate")
    public AjaxResult importTemplate()
    {
        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
        return util.importTemplateExcel("用户数据");
    }

    /**
     * 根据用户编号获取详细信息
     */
    @PreAuthorize("@ss.hasPermi('system:user:query')")
    @GetMapping(value = { "/", "/{userId}" })
    public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId)
    {
        AjaxResult ajax = AjaxResult.success();
        List<SysRole> roles = roleService.selectRoleAll();
        ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
        ajax.put("posts", postService.selectPostAll());
        if (StringUtils.isNotNull(userId))
        {
            ajax.put(AjaxResult.DATA_TAG, userService.selectUserById(userId));
            ajax.put("postIds", postService.selectPostListByUserId(userId));
            ajax.put("roleIds", roleService.selectRoleListByUserId(userId));
        }
        return ajax;
    }

    /**
     * 新增用户
     */
    @PreAuthorize("@ss.hasPermi('system:user:add')")
    @Log(title = "用户管理", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@Validated @RequestBody SysUser user)
    {
        if (StrUtil.isBlank(user.getPassword()) || !user.getPassword().matches("^(?![A-Za-z0-9]+$)(?![a-z0-9\\W]+$)(?![A-Za-z\\W]+$)(?![A-Z0-9\\W]+$)[a-zA-Z0-9\\W]{8,16}$")){
            throw new CustomException("密码必须由大小写字母、数字、特殊符号的8-16位组成");
        }
        if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user.getUserName())))
        {
            return AjaxResult.error("新增用户'" + user.getUserName() + "'失败，登录账号已存在");
        }
        else if (StringUtils.isNotEmpty(user.getPhonenumber())
                && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
        {
            return AjaxResult.error("新增用户'" + user.getUserName() + "'失败，手机号码已存在");
        }
        else if (StringUtils.isNotEmpty(user.getEmail())
                && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
        {
            return AjaxResult.error("新增用户'" + user.getUserName() + "'失败，邮箱账号已存在");
        }
        //校验客户角色添加用户情况
        checkCustomerAddUser(user.getRoleIds(),user.getDeptId());


        checkUser(user);
        //校验添加用户信息
        checkAddUser(user);


        user.setCreateBy(SecurityUtils.getUsername());
        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
        int i = userService.insertUser(user);
        return toAjax(i);
    }

    /**
     * 校验用户信息
     */
    private void checkUser(SysUser user) {
        //校验设计员添加用户情况
        SysUser currentUser = SecurityUtils.getLoginUser().getUser();
        checkCommonAddUser(currentUser,user);

        //校验现场工程师添加用户情况
        checkSceneAddUser(currentUser);

        //校验巡检员添加用户情况
        checkInspectorAddUser(currentUser);

        //校验安装工添加用户情况
        checkInstallerAddUser(currentUser);
    }

    private void checkInstallerAddUser(SysUser currentUser) {
        List<SysRole> roles = currentUser.getRoles();
        if (CollUtil.isEmpty(roles)){
            throw new CustomException("当前用户未分配角色");
        }
        SysRole sysRole = roles.get(0);
        if (sysRole.getRoleId().compareTo(installerRoleId) == 0){
            throw new CustomException("当前用户所属角色不能创建账号");
        }
    }

    /**
     * 校验添加用户信息
     *
     * @param sysUser
     */
    private void checkAddUser(SysUser sysUser){
        List<Long> newUserRoleIdList = Arrays.asList(sysUser.getRoleIds());
        //产品管理员角色
        if (newUserRoleIdList.contains(commonRoleId)){
            //校验添加产品管理员（设计员）用户时
            checkCommonUser(sysUser);
        }
        if (newUserRoleIdList.contains(customerRoleId)){
            //校验添加客户角色用户时
            checkCustomerUser(sysUser);

        }
        if (newUserRoleIdList.contains(inspectorRoleId)){
            //校验添加巡检员角色用户时
            checkInspectorUser(sysUser);

        }
        if (newUserRoleIdList.contains(sceneRoleId)){
            //校验添加现场工程师角色用户时
            checkSceneUser(sysUser);

        }
        if (newUserRoleIdList.contains(installerRoleId)){
            //校验添加安装工角色用户时
            checkInstallerUser(sysUser);

        }
    }

    private void checkInstallerUser(SysUser sysUser) {
        Long deptId = sysUser.getDeptId();
        boolean flag = sysDeptService.checkIsCustomer(deptId);
        if (!flag){
            throw new CustomException("安装工角色账号只能添加到客户公司中");
        }
    }

    /**
     * 校验巡检员添加用户情况(不能添加账号)
     *
     */
    private void checkInspectorAddUser(SysUser currentUser) {
        List<SysRole> roles = currentUser.getRoles();
        if (CollUtil.isEmpty(roles)){
            throw new CustomException("当前用户未分配角色");
        }
        SysRole sysRole = roles.get(0);
        if (sysRole.getRoleId().compareTo(inspectorRoleId) == 0){
            throw new CustomException("当前用户所属角色不能创建账号");
        }
    }

    /**
     * 校验现场工程师添加用户情况(不能添加账号)
     *
     */
    private void checkSceneAddUser(SysUser currentUser) {
        List<SysRole> roles = currentUser.getRoles();
        if (CollUtil.isEmpty(roles)){
            throw new CustomException("当前用户未分配角色");
        }
        SysRole sysRole = roles.get(0);
        if (sysRole.getRoleId().compareTo(sceneRoleId) == 0){
            throw new CustomException("当前用户所属角色不能创建账号");
        }
    }

    /**
     * 校验设计员添加用户情况（只能开客户账号）
     *
     * @param user
     */
    private void checkCommonAddUser(SysUser currentUser,SysUser user) {
        List<SysRole> roles = currentUser.getRoles();
        if (CollUtil.isEmpty(roles)){
            throw new CustomException("当前用户未分配角色");
        }
        SysRole sysRole = roles.get(0);
        if (sysRole.getRoleId().compareTo(commonRoleId) == 0){
            Long[] roleIds = user.getRoleIds();
            if(roleIds == null || roleIds.length == 0){
                throw new CustomException("新用户未分配角色");
            }
            Long roleId = roleIds[0];
            if (roleId.compareTo(customerRoleId) != 0){
                throw new CustomException("当前用户只能添加客户设备管理员角色账号");
            }
        }
    }

    /**
     * 校验客户只能添加巡检工角色的用户，并且数量上限为10
     *
     * @param newUserRoleIds 新用户的角色id
     * @param newDeptId 新用户部门id
     */
    private void checkCustomerAddUser(Long[] newUserRoleIds,Long newDeptId){
        LoginUser loginUser = SecurityUtils.getLoginUser();
        //获取当前登录用户的角色Id
        List<SysRole> roles = loginUser.getUser().getRoles();
        if (CollUtil.isEmpty(roles)){
            return;
        }
        List<Long> roleIdList = roles.stream().map(SysRole::getRoleId).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(roleIdList) && roleIdList.contains(customerRoleId)){
            //获取添加用户的角色Id
            List<Long> newUserRoleIdList = Arrays.asList(newUserRoleIds);
            if (!newUserRoleIdList.contains(inspectorRoleId) && !newUserRoleIdList.contains(installerRoleId)){
                throw new CustomException("添加失败！当前客户设备管理员只能添加客户巡检工和安装工角色用户");
            }
            Long deptId = loginUser.getUser().getDeptId();
            if (deptId.compareTo(newDeptId) != 0){
                throw new CustomException("添加失败！客户设备管理员只能添加本部门中的客户巡检工和安装工角色");
            }
            //验证是否限制10个巡检工用户
            List<SysUser> sysUsers = userService.queryXJUser(deptId, inspectorRoleId);
            if (CollUtil.isNotEmpty(sysUsers) && sysUsers.size() >= inspectorMaxSize){
                throw new CustomException("添加失败！当前客户设备管理员添加客户巡检工角色用户已达上限");
            }
        }
    }

    /**
     * 校验添加现场工程师角色用户
     *
     * @param sysUser
     */
    private void checkSceneUser(SysUser sysUser) {
        Long deptId = sysUser.getDeptId();
        boolean flag = sysDeptService.checkIsCustomer(deptId);
        if (flag){
            throw new CustomException("现场工程师角色账号不能添加到客户公司中");
        }
    }

    /**
     * 校验添加巡检工角色用户
     *
     * @param sysUser
     */
    private void checkInspectorUser(SysUser sysUser) {
        Long deptId = sysUser.getDeptId();
        boolean flag = sysDeptService.checkIsCustomer(deptId);
        if (!flag){
            throw new CustomException("客户巡检工角色账号只能添加到客户公司中");
        }
    }

    /**
     * 校验添加客户角色用户时
     *
     * @param sysUser
     */
    private void checkCustomerUser(SysUser sysUser){
        Long deptId = sysUser.getDeptId();
        boolean flag = sysDeptService.checkIsCustomer(deptId);
        if (!flag){
            throw new CustomException("客户设备管理员角色账号只能添加到客户公司中");
        }
    }

    /**
     * 校验添加产品管理员用户时
     *
     * @param sysUser
     */
    private void checkCommonUser(SysUser sysUser){
        Long deptId = sysUser.getDeptId();
        boolean flag = sysDeptService.checkIsCustomer(deptId);
        if (flag){
            throw new CustomException("设计员角色账号不能添加到客户公司中");
        }
    }

    /**
     * 修改用户
     */
    @PreAuthorize("@ss.hasPermi('system:user:edit')")
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@Validated @RequestBody SysUser user)
    {
        userService.checkUserAllowed(user);
        if (StringUtils.isNotEmpty(user.getPhonenumber())
                && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
        {
            return AjaxResult.error("修改用户'" + user.getUserName() + "'失败，手机号码已存在");
        }
        else if (StringUtils.isNotEmpty(user.getEmail())
                && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
        {
            return AjaxResult.error("修改用户'" + user.getUserName() + "'失败，邮箱账号已存在");
        }
        //判断当前用户是否属于客户公司
        SysUser currentUser = SecurityUtils.getLoginUser().getUser();
        boolean flag = sysDeptService.checkIsCustomer(currentUser.getDeptId());
        if (flag){
            Long customerId = sysDeptService.getCustomerId(currentUser.getDeptId());
            List<SysUser> sysUsers = userService.queryUserInfo(customerId);
            if (CollUtil.isEmpty(sysUsers)){
                throw new CustomException("当前用户所属的客户公司中没有可操作的用户");
            }
            Set<String> userNames = sysUsers.stream().map(SysUser::getUserName).collect(Collectors.toSet());
            if (!userNames.contains(user.getUserName())){
                throw new CustomException("当前用户没有权限操作此用户");
            }
        }
        checkUser(user);
        checkAddUser(user);
        user.setUpdateBy(SecurityUtils.getUsername());
        return toAjax(userService.updateUser(user));
    }

    /**
     * 删除用户
     */
    @PreAuthorize("@ss.hasPermi('system:user:remove')")
    @Log(title = "用户管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{userIds}")
    public AjaxResult remove(@PathVariable Long[] userIds)
    {
        return toAjax(userService.deleteUserByIds(userIds));
    }

    /**
     * 重置密码
     */
    @PreAuthorize("@ss.hasPermi('system:user:resetPwd')")
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @PutMapping("/resetPwd")
    public AjaxResult resetPwd(@RequestBody SysUser user)
    {
        if (StrUtil.isBlank(user.getPassword()) || !user.getPassword().matches("^(?![A-Za-z0-9]+$)(?![a-z0-9\\W]+$)(?![A-Za-z\\W]+$)(?![A-Z0-9\\W]+$)[a-zA-Z0-9\\W]{8,16}$")){
            throw new CustomException("密码必须由大小写字母、数字、特殊符号的8-16位组成");
        }
        userService.checkUserAllowed(user);
        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
        user.setUpdateBy(SecurityUtils.getUsername());
        int i = userService.resetPwd(user);

        return toAjax(i);
    }

    /**
     * 状态修改
     */
    @PreAuthorize("@ss.hasPermi('system:user:edit')")
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @PutMapping("/changeStatus")
    public AjaxResult changeStatus(@RequestBody SysUser user)
    {
        userService.checkUserAllowed(user);
        user.setUpdateBy(SecurityUtils.getUsername());
        return toAjax(userService.updateUserStatus(user));
    }
}
